package xyz.labmem.lipx.core.console

import cn.hutool.core.convert.Convert
import cn.hutool.core.util.StrUtil
import xyz.labmem.lipx.client.core.LabSSHPenetrationClient
import xyz.labmem.lipx.core.AppContext
import xyz.labmem.lipx.core.AppContext.Client.makeId
import xyz.labmem.lipx.core.AppContext.Client.parallelPool
import xyz.labmem.lipx.core.Status
import xyz.labmem.lipx.core.Type
import xyz.labmem.lipx.core.console.enums.Display
import xyz.labmem.lipx.core.console.enums.Display.LOGIN
import xyz.labmem.lipx.core.console.enums.Display.ROOT
import xyz.labmem.lipx.core.console.enums.DisplayClient
import xyz.labmem.lipx.core.console.enums.DisplayEnum
import xyz.labmem.lipx.core.console.enums.DisplayServer
import xyz.labmem.lipx.core.context.ServerContext.userList
import xyz.labmem.lipx.core.entity.ClientConfig
import xyz.labmem.lipx.core.tool.ConsoleProgressBar
import xyz.labmem.lipx.core.util.ClientConfigDataUtil
import xyz.labmem.lipx.core.util.ServerConfigDataUtil
import xyz.labmem.lipx.shutdown
import java.util.*

/**
 * @description: do something
 * @author: ltty
 * @date: 2022/8/9 11:40
 */
class Control {

    companion object {

        var checkGroup: Int = 0

        var cacheConfig: ClientConfig? = null

        fun render(de: DisplayEnum) {
            println("")
            if (StrUtil.isNotBlank(de.content())) println(de.content())
            if (StrUtil.isNotBlank(de.hint())) println(de.hint())
            print("lipx:/${de.getName().lowercase()}$ ")
            val console = Scanner(System.`in`)
            if (!parse(console.nextLine() ?: "", de)) {
                println(
                    """
                    【 未知命令，请检查后再试！】
                """.trimIndent()
                )
                render(de)
            }
        }


        private fun parse(input: String, de: DisplayEnum): Boolean {

            val inputList = input.trim().split(" ")
            val key = inputList[0]
            return if (de.keys().contains(key) || de.keys().contains("{input}")) {
                try {
                    when (de) {
                        is Display -> {
                            when (de) {
                                ROOT -> {
                                    when (key) {
                                        "1" -> render(DisplayServer.STATUS)
                                        "2" -> render(DisplayClient.LIST)
                                        "3" -> render(LOGIN)
                                        "log" -> render(Display.LOG)
                                        "exit" -> shutdown()
                                    }
                                }

                                LOGIN -> login(inputList, de)
                                Display.LOG -> render(ROOT)
                            }
                        }

                        is DisplayServer -> {
                            when (de) {
                                DisplayServer.CONFIG -> serverConfig(inputList, de)
                                DisplayServer.STATUS -> serverStatus(inputList, de)
                            }
                        }

                        is DisplayClient -> {
                            when (de) {
                                DisplayClient.ADD_GROUP_NAME -> clientGroup(inputList, de)
                                DisplayClient.ADD_NAME -> clientName(inputList, de)
                                DisplayClient.ADD_SERVER_HOST -> clientServerHost(inputList, de)
                                DisplayClient.ADD_SERVER_PORT -> clientServerPort(inputList, de)
                                DisplayClient.ADD_PROXY_HOST -> clientProxyHost(inputList, de)
                                DisplayClient.ADD_PROXY_PORT -> clientProxyPort(inputList, de)
                                DisplayClient.ADD_TARGET_PORT -> clientTargetPort(inputList, de)
                                DisplayClient.ADD_PASSWORD -> clientPassword(inputList, de)
                                DisplayClient.ADD_WLS -> clientWLS(inputList, de)
                                DisplayClient.SAVE -> if (inputList[0].lowercase() == "y" || inputList[0] == "") {
                                    ClientConfigDataUtil.write(cacheConfig!!)
                                    cacheConfig = null
                                    render(DisplayClient.LIST)
                                } else if (inputList[0].lowercase() == "n") {
                                    cacheConfig = null
                                    render(DisplayClient.LIST)
                                }

                                DisplayClient.LIST -> clientList(inputList, de)
                                DisplayClient.INFO -> clientInfo(inputList, de)
                                DisplayClient.ADD_AUTO -> clientAuto(inputList)
                                DisplayClient.ADD_TYPE -> clientType(inputList)
                            }
                        }
                    }
                } catch (e: Exception) {
//                    e.printStackTrace()
                    render(de)
                }
                true
            } else false
        }

        fun enquire(q: String): Boolean {
            println("$q 【y/n】")
            val nextLine = Scanner(System.`in`).nextLine()
            return nextLine.trim() == "y" || StrUtil.isBlank(nextLine)
        }

        private fun login(il: List<String>, de: DisplayEnum) {

        }

        private fun serverConfig(il: List<String>, de: DisplayEnum) {
            when (il[0]) {
                "edit" -> {
                    when (il[1]) {
                        "port" -> {
                            addServerCommon(il[2], de, "port") {
                                AppContext.Server.cacheData?.port = Convert.toInt(il[2])
                                render(de)
                            }
                        }

                        "pwd" -> {
                            addServerCommon(il[2], de) {
                                AppContext.Server.cacheData?.password = il[2]
                                render(de)
                            }
                        }

                        "wls" -> {
                            addServerCommon(il[2], de, "list") {
                                AppContext.Server.cacheData?.wls = if (il[2] == "null" || il[2] == "[]")
                                    HashSet() else HashSet(il[2].split(","))
                                render(de)
                            }
                        }

                        "auto" -> {
                            addServerCommon(il[2], de, "bol") {
                                AppContext.Server.cacheData?.autoRun = !(il[2] == "0" || il[2] == "false")
                                render(de)
                            }
                        }
                    }
                }

                "save" -> {
                    AppContext.Server.cacheData?.let {
                        ServerConfigDataUtil.write(it)
                        println("【保存成功！】")
                        if (enquire("是否重新启动服务？"))
                            AppContext.Server.server.restart(it)
                    }
                    render(de)
                }

                "back", "./" -> {
                    if (!enquire("是否放弃修改？")) {
                        render(de)
                    } else {
                        ServerConfigDataUtil.refreshData()
                        render(DisplayServer.STATUS)
                    }
                }
            }
        }

        private fun serverStatus(il: List<String>, de: DisplayEnum) {
            when (il[0]) {
                "config", "c" -> {
                    render(DisplayServer.CONFIG)
                }

                "start" -> {
                    AppContext.Server.cacheData?.let { AppContext.Server.server.start(it) }
                    render(de)
                }

                "close" -> {
                    if (userList.size == 0 || enquire("是否关闭服务？"))
                        AppContext.Server.server.close()
                    render(de)
                }

                "r" -> {
                    render(de)
                }

                "back", "./" -> {
                    render(ROOT)
                }
            }
        }

        private fun addClientCommon(
            il: List<String>,
            de: DisplayEnum,
            type: String = "string",
            index: Int = 0,
            run: () -> Unit
        ) {
            if (index >= il.size) {
                println("不能为空请重新输入！")
                render(de)
            }
            if (il[0] == "!Q") {
                cacheConfig = null
                render(DisplayClient.LIST)
            } else if (il[0] == "!R") {
                render(DisplayClient.ADD_NAME)
            } else if (type == "string" && il[index].length > 64) {
                println("输入字符长度不能超过64！")
                render(de)
            } else if (type == "list") {
                if (il[index].length > 255) {
                    println("输入字符长度不能超过255！")
                    render(de)
                } else {
                    try {
                        HashSet(il[index].split(","))
                        run()
                    } catch (i: Exception) {
                        println("输入数组错误！示例: 127.0.0.1,127.0.0.2 若为空输入:null或[] ")
                        render(de)
                    }
                }
            } else if (type == "int" || type == "port") {
                try {
                    Convert.toInt(il[index])
                    if (type == "port" && il[index].toInt() <= 0 || il[index].toInt() > 65535) {
                        println("输入端口不正确！")
                        render(de)
                    } else
                        run()
                } catch (e: Exception) {
                    println("输入数字不正确！")
                    render(de)
                }
            } else {
                run()
            }
        }

        private fun addServerCommon(il: String, de: DisplayEnum, type: String = "string", run: () -> Unit) {
            if (il.length > 64 && type == "string") {
                println("输入字符长度不能超过64！")
                render(de)
            } else if (il != "0" && il != "1" && il.lowercase() != "true" && il.lowercase() != "false" && type == "bol") {
                println("请输入1/0 或者 true/false !")
                render(de)
            } else if (type == "list") {
                if (il.length > 255) {
                    println("输入字符长度不能超过255！")
                    render(de)
                } else {
                    try {
                        HashSet(il.split(","))
                        run()
                    } catch (i: Exception) {
                        println("输入数组错误！示例: 127.0.0.1,127.0.0.2 若为空输入:null或[] ")
                        render(de)
                    }
                }
            } else if (type == "int" || type == "port") {
                try {
                    Convert.toInt(il)
                    if (type == "port" && il.toInt() <= 0 || il.toInt() > 65535) {
                        println("输入端口不正确！")
                        render(de)
                    } else
                        run()
                } catch (e: Exception) {
                    println("输入数字不正确！")
                    render(de)
                }
            } else {
                run()
            }
        }

        private fun clientName(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de) {
                cacheConfig = ClientConfig()
                cacheConfig!!.id = AppContext.Client.makeId()
                cacheConfig!!.remark = il[0]
                render(DisplayClient.ADD_GROUP_NAME)
            }
        }

        private fun clientGroup(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de) {
                if (il[0] != "")
                    cacheConfig!!.group = il[0]
                render(DisplayClient.ADD_TYPE)
            }
        }

        private fun clientServerHost(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de) {
                cacheConfig!!.serverHost = il[0]
                render(DisplayClient.ADD_SERVER_PORT)
            }
        }

        private fun clientServerPort(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de, "port") {
                cacheConfig!!.serverPort = il[0].toInt()
                render(DisplayClient.ADD_PROXY_HOST)
            }
        }

        private fun clientProxyHost(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de) {
                cacheConfig!!.proxyHost = if (il[0] == "") "127.0.0.1" else il[0]
                render(DisplayClient.ADD_PROXY_PORT)
            }
        }

        private fun clientProxyPort(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de, "port") {
                cacheConfig!!.proxyPort = il[0].toInt()
                render(DisplayClient.ADD_TARGET_PORT)
            }
        }

        private fun clientTargetPort(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de, "port") {
                cacheConfig!!.targetPort = il[0].toInt()
                render(DisplayClient.ADD_PASSWORD)
            }
        }

        private fun clientPassword(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de) {
                cacheConfig!!.password = il[0]
                render(DisplayClient.ADD_WLS)
            }
        }

        private fun clientWLS(il: List<String>, de: DisplayEnum) {
            addClientCommon(il, de, "list") {
                cacheConfig!!.wls = if (il[0] == "null" || il[0] == "[]" || StrUtil.isBlank(il[0]))
                    HashSet() else HashSet(il[0].split(","))
                render(DisplayClient.ADD_AUTO)
            }
        }

        private fun clientType(il: List<String>) {
            cacheConfig!!.type = if (il[0] == "1") Type.FORWARD else Type.REVERSE
            render(DisplayClient.ADD_SERVER_HOST)
        }

        private fun clientAuto(il: List<String>) {
            cacheConfig!!.autoRun = (il[0] == "true")
            render(DisplayClient.SAVE)
        }

        private fun clientList(il: List<String>, de: DisplayEnum) {
            when (il[0]) {
                "group", "g" -> {
                    try {
                        val index = il[1].toInt()
                        if (AppContext.Client.groupList.size > index) {
                            checkGroup = index
                        } else
                            println("【 group index不正确，请重新输入 】")
                    } catch (e: Exception) {
                        println("【 group index不正确，请重新输入 】")
                    }
                    render(de)
                }

                "info", "i" -> {
                    if (AppContext.Client.allList.containsKey(il[1])) {
                        AppContext.Client.infoCache = AppContext.Client.allList[il[1]]!!
                        render(DisplayClient.INFO)
                    } else {
                        println("【 ID不正确，请重新输入 】")
                        render(de)
                    }
                }

                "new", "n" -> {
                    render(DisplayClient.ADD_NAME)
                }

                "copy", "cp" -> {
                    if (AppContext.Client.allList.containsKey(il[1])) {
                        println("正在复制配置信息")
                        AppContext.Client.infoCache = AppContext.Client.allList[il[1]]!!
                        AppContext.Client.cacheCopy = true
                        render(DisplayClient.INFO)
                    } else {
                        println("【 ID不正确，请重新输入 】")
                        render(de)
                    }
                }

                "del", "d" -> {
                    if (AppContext.Client.allList.containsKey(il[1])) {
                        val data = AppContext.Client.allList[il[1]]!!
                        if (enquire("是否删除'${data.remark}'?")) {
                            if (data.status == Status.CONNECTED || data.status == Status.CONNECTING)
                                AppContext.Client.connectList[data.id]?.close()
                            ClientConfigDataUtil.delById(data.id!!)
                            ClientConfigDataUtil.refreshList()
                            println("删除成功")
                        }
                    } else {
                        println("【 ID不正确，请重新输入 】")
                    }
                    render(de)
                }

                "start", "s" -> {
                    val bar = ConsoleProgressBar(100, '✪', "正在启动连接..") {
                        render(de)
                    }
                    if (il[1] == "all") {
                        val filter =
                            AppContext.Client.allList.filter { (it.value.status == Status.IDLE || it.value.status == Status.FAILED) && it.value.group == AppContext.Client.groupList[checkGroup] }
                        if (filter.isNotEmpty()) {
                            bar.setValueSize(filter.size)
                            bar.show(1.0)
                            filter.forEach { (_, v) ->
                                parallelPool.execute {
                                    LabSSHPenetrationClient(v).connect { bar.step() }
                                }
                            }
                        } else
                            render(de)
                    } else {
                        if (AppContext.Client.allList.containsKey(il[1])) {
                            val config = AppContext.Client.allList[il[1]]!!
                            if (config.status == Status.IDLE || config.status == Status.FAILED) {
                                bar.setValueSize(1)
                                bar.show(30.0)
                                LabSSHPenetrationClient(config).connect { bar.step() }
                            } else {
                                println("【 ${il[1]} ${config.remark} 】 ${config.status.getCN()}")
                                render(de)
                            }
                        } else {
                            println("【 ID不正确，请重新输入 】")
                            render(de)
                        }
                    }
                }

                "cut", "c" -> {
                    if (il[1] == "all") {
                        if (AppContext.Client.connectList.isNotEmpty()) {
                            val bar = ConsoleProgressBar(100, '✄', "正在断开连接..") {
                                render(de)
                            }
                            bar.setValueSize(AppContext.Client.connectList.size)
                            bar.show(1.0)
                            AppContext.Client.connectList.forEach { (id, u) ->
                                if (AppContext.Client.allList[id]?.group == AppContext.Client.groupList[checkGroup]) {
                                    parallelPool.execute {
                                        u.close()
                                        bar.step()
                                    }
                                }
                            }
                        } else
                            render(de)
                    } else {
                        if (AppContext.Client.connectList.containsKey(il[1])) {
                            AppContext.Client.connectList[il[1]]!!.close()
                            render(de)
                        } else {
                            println("【 该ID没有连接，请重新输入 】")
                            render(de)
                        }
                    }

                }

                "back", "./" -> {
                    render(ROOT)
                }

                "r" -> {
                    render(de)
                }
            }
        }

        private fun clientInfo(il: List<String>, de: DisplayEnum) {
            when (il[0]) {
                "edit" -> {
                    when (il[1]) {
                        "name" -> {
                            addClientCommon(il, de, index = 2) { AppContext.Client.infoCache?.remark = il[2] }
                        }

                        "group" -> {
                            addClientCommon(il, de, index = 2) { AppContext.Client.infoCache?.group = il[2] }
                        }

                        "type" -> {
                            addClientCommon(il, de, index = 2) {
                                AppContext.Client.infoCache?.type = if (il[2] == "1") Type.FORWARD else Type.REVERSE
                            }
                        }

                        "sip" -> {
                            addClientCommon(il, de, index = 2) { AppContext.Client.infoCache?.serverHost = il[2] }
                        }

                        "spt" -> {
                            addClientCommon(il, de, "port", 2) {
                                AppContext.Client.infoCache?.serverPort = il[2].toInt()
                            }
                        }

                        "pip" -> {
                            addClientCommon(il, de, index = 2) { AppContext.Client.infoCache?.proxyHost = il[2] }
                        }

                        "ppt" -> {
                            addClientCommon(il, de, "port", index = 2) {
                                AppContext.Client.infoCache?.proxyPort = il[2].toInt()
                            }
                        }

                        "tpt" -> {
                            addClientCommon(il, de, "port", index = 2) {
                                AppContext.Client.infoCache?.targetPort = il[2].toInt()
                            }
                        }

                        "pwd" -> {
                            addClientCommon(il, de, index = 2) { AppContext.Client.infoCache?.password = il[2] }
                        }

                        "auto" -> {
                            addClientCommon(il, de, index = 2) {
                                AppContext.Client.infoCache?.autoRun = (il[2] == "true")
                            }
                        }

                        "wls" -> {
                            addClientCommon(il, de, "list", index = 2) {
                                AppContext.Client.infoCache?.wls =
                                    if (il[2] == "null" || il[2] == "[]" || StrUtil.isBlank(il[2]))
                                        HashSet() else HashSet(il[2].split(","))
                            }
                        }
                    }
                    render(de)
                }

                "save" -> {
                    if (AppContext.Client.cacheCopy) {
                        AppContext.Client.infoCache?.id = makeId()
                        AppContext.Client.cacheCopy = false
                    }
                    ClientConfigDataUtil.write(AppContext.Client.infoCache!!)
                    if (AppContext.Client.connectList.containsKey(AppContext.Client.infoCache?.id!!)) {
                        if (enquire("是否重新连接该配置？"))
                            AppContext.Client.connectList[AppContext.Client.infoCache?.id!!]!!.restart(AppContext.Client.infoCache!!)
                    }
                    render(DisplayClient.LIST)
                }

                "back", "./" -> {
                    render(DisplayClient.LIST)
                }
            }
        }

    }
}